Add Deck for multi-slide and multi-image output#18
Open
sjquant wants to merge 6 commits into
Open
Conversation
Introduce a Deck container that collects Canvas slides and exports them to a multi-page PDF, a multi-slide PPTX, a numbered raster sequence, or a single contact-sheet grid. Slides may have mixed sizes; diagnose() aggregates per-slide findings and warns on size mismatch. Refactor the PDF and PPTX exporters to emit one page/slide per canvas while keeping the single-canvas API unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLVAwDncqBSdzXnid1YMFB
- render(): drop the format-based dispatch escape hatch, reject a raster format override on document output, and give .svg its own clear error. - slides property returns a copy so the Canvas type guard can't be bypassed. - contact_sheet validates image paths up front for consistent errors. - PPTX exporter no longer validates the first slide twice. - Document that mixed-size decks clip larger later slides in PPTX. - Add tests for render dispatch, to_pptx() bytes, and column clamping. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLVAwDncqBSdzXnid1YMFB
Add an optional default size to Deck (Deck(width, height) and Deck.from_aspect_ratio) so slides can be written as bare Canvas() that inherit it, instead of repeating dimensions on every slide. An explicitly sized canvas keeps its own size. Canvas now accepts being constructed without a size: it stays "unsized" (accepting layer builders but refusing render/diagnose/serialize with a clear error) until a size is assigned directly or injected when the canvas is added to a sized deck. The Deck constructor takes width/height first; pre-built canvases now pass via Deck(slides=[...]). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLVAwDncqBSdzXnid1YMFB
- Drop the dummy first-slide arg from the multi-canvas exporter calls by making PdfExporter/PptxExporter accept an optional canvas; single-canvas save()/export_bytes() now guard for it explicitly. - Preserve a deck's default size and a deck-level theme across to_json/ from_json; the shared theme resolves $theme.* tokens in every slide. - Share one aspect_ratio_dimensions() helper between Canvas and Deck and raise ValidationError for malformed ratios. - Pre-validate all slide assets before writing a raster sequence so a failing slide leaves no partial output on disk. - contact_sheet() accepts an (R,G,B[,A]) tuple and validates the background eagerly instead of failing opaquely at render time. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLVAwDncqBSdzXnid1YMFB
The contact-sheet grid was speculative surface area: nothing in the library, examples, or workflows used it, and a proof-sheet image is a separate concern from the multi-page/multi-slide/sequence outputs the deck exists for. Drop the method, its private helpers, the now-unused PIL import, and the related tests and docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLVAwDncqBSdzXnid1YMFB
Deck(slides=[...]) already covers seeding several slides at once and .slide() covers appending one, so a separate variadic add() was redundant surface area. Drop it and update tests and docs to use the constructor or chained slide() calls. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLVAwDncqBSdzXnid1YMFB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
quickthumb could render a single canvas to PPTX (one slide) and PDF (one page), but had no way to produce a multi-slide deck or a batch of related images from several canvases. This adds a thin container that sequences existing canvases into multi-output documents and image sets, reusing the entire per-canvas render pipeline so each slide looks identical to rendering that canvas on its own.
Changes
Deck(quickthumb/deck.py), exported from the package alongsideDeckDiagnostic:Deck([...]),.slide(canvas),.add(*canvases); supportslen(), indexing, and iteration.render(path)dispatches on extension:.pdf→ one multi-page PDF,.pptx→ one multi-slide PPTX, raster (.png/.jpg/.jpeg/.webp) → a zero-padded numbered sequence (slides_01.png, …), returning the written paths.to_pdf()/to_pptx()return document bytes;contact_sheet(columns=…)composes all slides into a single gridCanvas.diagnose()aggregates each slide's findings tagged withslide_index, plus amixed-slide-sizewarning when slide dimensions differ (PPTX uses the first slide's size for the whole deck).to_json()/from_json()round-trip via each canvas's serialization.save_canvases/export_bytes_canvases); the single-canvas API is unchanged.tests/test_deck.pyadds black-box coverage for composition, the numbered raster sequence, PDF/PPTX page counts, mixed-size handling, diagnostics, contact sheet, and JSON round-trip.docs/api/deck.mdreference page (wired into nav and the API overview), and a Decks section indocs/exports.md.🤖 Generated with Claude Code
https://claude.ai/code/session_01RLVAwDncqBSdzXnid1YMFB
Generated by Claude Code